﻿using CodeGenerator.DBInfo.entity;
using CodeGenerator.Utils;
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;

namespace CodeGenerator.DBInfo
{
    /// <summary>
    /// MySQL数据库信息获取类
    /// </summary>
    internal class MySQLDBInfoGetter : AbstractDbInfoGetter<MySqlConnection, MySqlDataAdapter>, IDBInfoGetter
    {
        //数据列类型与Java类型映射
        readonly Dictionary<string, string> JavaTypeMappings = new Dictionary<string, string>
            {
                { "TINYINT", "boolean" },
                { "SMALLINT", "Short" },
                { "MEDIUMINT", "Integer" },
                { "INT", "Integer" },
                { "INTEGER", "Integer" },
                { "BIGINT", "Long" },
                { "FLOAT", "Float" },
                { "DOUBLE", "Double" },
                { "DECIMAL", "Double" },
                { "CHAR", "String" },
                { "VARCHAR", "String" },
                { "TINYTEXT", "String" },
                { "TEXT", "String" },
                { "MEDIUMTEXT", "String" },
                { "LONGTEXT", "String" },
                { "DATE", "LocalDateTime" },
                { "DATETIME", "LocalDateTime" },
                { "TIMESTAMP", "LocalDateTime" },
                { "TIME", "LocalDateTime" },
                { "YEAR", "LocalDateTime" },
                { "BINARY", "byte[]" },
                { "VARBINARY", "byte[]" },
                { "TINYBLOB", "byte[]" },
                { "BLOB", "byte[]" },
                { "MEDIUMBLOB", "byte[]" },
                { "LONGBLOB", "byte[]" },
                { "ENUM", "String" },
                { "SET", "String" },
                { "BIT", "boolean" },
                { "JSON", "String" }
            };
        public MySQLDBInfoGetter(ConnectionInfo connInfo) : base(connInfo)
        {
        }

        public override MySqlConnection Connect()
        {
            MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder();
            builder.UserID = ConnInfo.UserName;
            builder.Password = ConnInfo.Password;
            builder.Server = ConnInfo.Host;
            builder.Port = ConnInfo.Port;
            return new MySqlConnection(builder.ConnectionString);
        }

        public override MySqlDataAdapter GetDataAdapter(string sql, IDbConnection conn)
        {
            return new MySqlDataAdapter(sql, conn as MySqlConnection);
        }


        public override List<string> GetDbList()
        {
            List<string> list = new List<string>();
            var dt = Query("show databases");
            foreach (DataRow row in dt.Rows)
            {
                list.Add(row["Database"].ToString());
            }
            return list;
        }

        public override string GetJavaType(ColumnInfo column)
        {
            return JavaTypeMappings.TryGetValue(column.Type.ToUpper(), out var type) ? type.ToString() : "String";
        }

        public override string GetJavaScriptType(ColumnInfo column)
        {
            var javaType = GetJavaType(column).ToLower();
            var numberTypes = new string[] { "double", "integer", "float", "short" };
            if (numberTypes.Contains(javaType))
            {
                return "number";
            }
            else if (javaType == "boolean")
            {
                return "boolean";
            }
            return "string";
        }

        public override List<string> GetSchemaList(string dbName)
        {
            throw new NotImplementedException();
        }

        public override TableInfo GetTableInfo(string db, string schema, string table)
        {
            string tableComment = null;
            var dt = Query($@"select
			                    t.TABLE_SCHEMA OWNER,
			                    t.TABLE_NAME NAME,
			                    CURRENT_USER CREATED,
			                    t.TABLE_COMMENT COMMENTS
		                     from
			                    information_schema. TABLES t
		                     where
			                    t.TABLE_SCHEMA = '{db}'");

            foreach (DataRow row in dt.Rows)
            {
                if (row["NAME"].ToString() == table)
                {
                    tableComment = row["COMMENTS"].ToString();
                }
            }
            foreach (DataRow row in dt.Rows)
            {
                if (row["NAME"].ToString() == table)
                {
                    tableComment = row["COMMENTS"].ToString();
                }
            }
            if (tableComment == null)
            {
                throw new Exception($"表 {table} 不存在！");
            }
            dt = Query($@"select
			                a.COLUMN_NAME,
			                a.DATA_TYPE,
			                a.CHARACTER_MAXIMUM_LENGTH DATA_LENGTH,
			                a.NUMERIC_PRECISION DATA_PRECISION,
			                a.NUMERIC_SCALE DATA_SCALE,
			                a.IS_NULLABLE NULLABLE,
			                a.COLUMN_COMMENT COMMENTS,
			                a.COLUMN_DEFAULT DATA_DEFAULT,
			                a.ORDINAL_POSITION COLUMN_ID,
			                a.COLUMN_KEY
		                from
				                information_schema.`COLUMNS` A
		                where
			                A.TABLE_SCHEMA = '{db}'
			                and
				                A.TABLE_NAME = '{table}'
                        order by ordinal_position");
            var columns = new List<ColumnInfo>();
            var primaryKeyCount = 0;
            foreach (DataRow row in dt.Rows)
            {
                string precision = row["DATA_PRECISION"].ToString();
                string scale = row["DATA_SCALE"].ToString();
                var isPk = row["COLUMN_KEY"].ToString() == "PRI";
                if (isPk) primaryKeyCount++;
                columns.Add(new ColumnInfo()
                {
                    Name = row["COLUMN_NAME"].ToString(),
                    Type = row["DATA_TYPE"].ToString(),
                    IsPrimaryKey = isPk,
                    IsAllowNull = row["NULLABLE"].ToString() == "YES",
                    Comment = row["COMMENTS"].ToString(),
                    NumLength = precision.IsNullOrEmpty() ? -1 : int.Parse(precision.ToString()),
                    NumScale = scale.IsNullOrEmpty() ? -1 : int.Parse(scale.ToString())
                });
            }
            return new TableInfo()
            {
                Name = table,
                TrimPrefixName = table,
                Comment = tableComment,
                Columns = columns,
                PrimaryKeyCount = primaryKeyCount
            };
        }

        public override List<dynamic> GetTableList(string parentName)
        {
            var list = new List<dynamic>();
            var dt = Query($@"select
			                    t.TABLE_SCHEMA OWNER,
			                    t.TABLE_NAME NAME,
			                    CURRENT_USER CREATED,
			                    t.TABLE_COMMENT COMMENTS
		                     from
			                    information_schema. TABLES t
		                     where
			                    t.TABLE_SCHEMA = '{parentName}'");

            foreach (DataRow row in dt.Rows)
            {
                list.Add(new { Name = row["NAME"].ToString(), Comment = row["COMMENTS"].ToString() });
            }
            return list;
        }

        public override void TestConnection()
        {
            var conn = Connect();
            conn.Open();
            conn.Close();
        }
    }
}
